/*
 *  Copyright (C) 2011 glauco
 * 
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 * 
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 * 
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.balisunrise.swing.builders;

import java.util.ArrayList;
import java.util.List;
import javax.swing.JTable;
import org.balisunrise.annotation.EventType;
import org.balisunrise.annotation.util.AnnotationsUtilitiesException;
import org.balisunrise.annotation.util.ColumnUtilities;
import org.balisunrise.annotation.util.GridUtilities;
import org.balisunrise.annotation.util.NameUtil;
import org.balisunrise.application.Application;
import org.balisunrise.builder.BuilderException;
import org.balisunrise.builder.FactoryException;
import org.balisunrise.common.Action;
import org.balisunrise.common.ActionProvider;
import org.balisunrise.common.Grid;
import org.balisunrise.common.GridColumn;
import org.balisunrise.swing.commons.GridModel;
import org.balisunrise.swing.commons.listeners.GridColumnListener;
import org.balisunrise.swing.commons.listeners.GridSelectionListener;
import org.balisunrise.swing.components.ComponentFactory;

/**
 *
 * @author glauco
 */
public class GridBuilder implements org.balisunrise.builder.GridBuilder{

    private static final String MESSAGE = "Erro ao construir um BaliGrid.\n";

    @Override
    public Grid create(Class entityClass, String alias)
            throws BuilderException {

        if(entityClass == null){
            throw new BuilderException(MESSAGE +
                    "entityClass não pode ser nulo.");
        }

        if(alias == null){
            throw new BuilderException(MESSAGE +
                    "alias não pode ser nulo.");
        }

        try{
            GridUtilities gu = GridUtilities.create(entityClass, alias);
            return create(gu);
        }catch(AnnotationsUtilitiesException aue){
            throw new BuilderException(MESSAGE +
                    aue.getMessage(), aue.getCause());
        }
    }

    @Override
    public Grid create(GridUtilities gu)
            throws BuilderException {

        if(gu == null){
            throw new BuilderException(MESSAGE +
                    "GridUtilities não pode ser nulo.");
        }

        // GRID
        org.balisunrise.swing.commons.Grid grid =
                new org.balisunrise.swing.commons.Grid();

        // ATRIBUICAO BASICA
        grid.setAlias(gu.alias);
        grid.setEntityClass(gu.entityClass);
        grid.setTitle(gu.title);

        // CRIA GRID MODEL
        GridModel model = new GridModel();
        model.setAlias(gu.alias);
        model.setEntityClass(gu.entityClass);
        model.setName(gu.entityClass.getName() + "_MODEL_" + gu.alias);
        model.setOwner(grid);

        // CRIA AS COLUNAS
        List<GridColumn> columns = new ArrayList<GridColumn>();
        for (ColumnUtilities cUtil : gu.columns) {
            try{
                GridColumn[] cols = Application.get().getFactory()
                    .createGridColumn(gu.entityClass, cUtil);
                for (GridColumn col : cols) {
                    col.setOwner(model);
                    columns.add(col);
                }
            }catch (FactoryException fex){
                throw new BuilderException(MESSAGE + "\n"
                        + fex.getMessage(),fex);
            }
        }

        // ATRIBUI AS COLUNAS AO GRID
        model.setColumns(columns.toArray(new GridColumn[]{}));

        // ATRIBUI MODEL AO GRID
        grid.setGridModel(model);

        // provedor de ações
        ActionProvider ap = Application.get().getActionMapManager()
                .getActionProvider(gu.entityClass);

        // cria listener das ações de selecionar linha
        GridSelectionListener gsl = new GridSelectionListener();
        grid.addSelectionListener(gsl);

        // ações de eventos de seleção de linha
        Action[] as = ap.getActions(EventType.GRID_LINE_SELECTED,
                gu.alias, null);
        for (Action action : as) {
            action.setOwner(grid);
            gsl.addLineSelectedAction(action);
        }

        // ações de eventos de seleção da última linha
        as = ap.getActions(EventType.GRID_LAST_LINE_SELECTED, gu.alias, null);
        for (Action action : as) {
            action.setOwner(grid);
            gsl.addLastLineSelectedAction(action);
        }
        
        // listener de ações de selecionar colunas
        GridColumnListener gcl = new GridColumnListener();
        grid.addColumnListener(gcl);

        // ações de seleção de coluna
        as = ap.getActions(EventType.GRID_COLUMN_SELECTED, gu.alias, null);
        for (Action action : as) {
            action.setOwner(grid);
            gcl.addColumnSelectedAction(action);
        }

        // ações de seleção da ultima coluna
        as = ap.getActions(EventType.GRID_LAST_COLUMN_SELECTED, gu.alias, null);
        for (Action action : as) {
            action.setOwner(grid);
            gcl.addLastColumnSelectedAction(action);
        }

        // ações de seleção da ultima coluna editavel
        as = ap.getActions(EventType.GRID_LAST_EDITABLE_COLUMN_SELECTED,
                gu.alias, null);
        for (Action action : as) {
            action.setOwner(grid);
            gcl.addLastEditableColumnSelectedAction(action);
        }

        // CRIA REPRESENTACAO VISUAL
        JTable table = ComponentFactory.gridTable(model, gu.height);
        //FocusTraversalKeys.setFocusTraversalKeys(table);

        // ATRIBUI NOME, REPRESENTACAO VISUAL
        String name = NameUtil.buildName(grid);
        grid.setName(name);
        table.setName(name);
        table.getAccessibleContext().setAccessibleName(name);
        table.getAccessibleContext().setAccessibleDescription(gu.title);
        grid.setVisualRepresentation(table);

        return grid;
    }

}
